const Koa = require('koa');
const app = new Koa();
const views = require('koa-views');
const json = require('koa-json');
const onerror = require('koa-onerror');
const bodyparser = require('koa-bodyparser')();
const logger = require('koa-logger');

const index = require('./routes/index');
const users = require('./routes/users');

const path = require('path');
global.configs = require('../../configs');

// error handler
onerror(app);

// middlewares
app.use(bodyparser);
app.use(json());
app.use(logger());
if (process.env.NODE_ENV === 'production') {
  const webpackIsomorphic = require('webpack-isomorphic');
  webpackIsomorphic.install(path.join(__dirname, 'build/client'), {
    cache: true //process.env['NODE_ENV'] !== 'development'
  });
  app.use('/assets', function (req, res, next) {
    res.sendStatus(404);
  });
  app.use(require('koa-static')(path.join(configs.Server.SERVER_DIR, './public')));
} else {
  const webpack = require('webpack'),
    webpackDevMiddleware = require('webpack-dev-middleware'),
    webpackHotMiddleware = require('webpack-hot-middleware'),
    webpackDevConfig = require(path.join(configs.Server.SERVER_DIR, './webpack.config.js'));
  const compiler = webpack(webpackDevConfig);
  const devMiddleWare = function (compiler, opt) {
    let dev = webpackDevMiddleware(compiler, opt);
    return async(ctx, next) => {
      await new Promise((resolve) => {
        dev(ctx.req, {
          end: (content) => {
            ctx.body = content;
            resolve(false);
          },
          setHeader: (name, value) => {
            ctx.set(name, value);
          },
          locals: ctx.state
        }, () => {
          resolve(true);
        })
      });
      let shouldNext = await devMiddleWare
      if (shouldNext) {
        return await next();
      } else {
        return null;
      }
    }
  }
  const hotMiddleWare = function (compiler, opt) {
    const hot = webpackHotMiddleware(compiler, opt);
    return async(ctx, next) => {
      await new Promise((resolve) => {
        hot(ctx.req, {
          write: (content) => {
            ctx.res.write(content);
          },
          writeHead: (status, headers) => {
            ctx.status = status
            ctx.set(headers)
          }
        }, resolve);
      });
      return await next();
    }
  }
  // attach to the compiler & the server
  app.use(devMiddleWare(compiler, {
    // public path should be the same with webpack config
    publicPath: webpackDevConfig.output.publicPath,
    noInfo: true,
    stats: {
      colors: true
    }
  }));
  app.use(hotMiddleWare(compiler, {
    log: console.log,
    heartbeat: 1500
  }));
  app.use(require('koa-static')(path.join(configs.Server.SERVER_DIR, './public')));
}


app.use(views(path.join(configs.Server.SERVER_DIR, './views'), {
  extension: 'ejs'
}));

// logger
app.use(async(ctx, next) => {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});

// routes
app.use(index.routes(), index.allowedMethods());
app.use(users.routes(), users.allowedMethods());

module.exports = app;